package com.hontech.libratest.conn

import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import com.hontech.libratest.app.AppContext
import com.hontech.libratest.except.AckException
import com.hontech.libratest.except.RespException
import com.hontech.libratest.utils.*
import java.io.IOException

object Device : BroadcastReceiver() {

    const val USB_PERMISSION_ACTION = "usb.permission.action"

    var openFlag = false
        private set

    var destAddr = 7

    private var usbDevice: UsbDevice? = null
    private var openFn = { flag: Boolean -> }
    private var port: FtdiSerialDevice? = null
    private val ackSync = Sync()
    private val respSync = RespSync()
    private var reader: PortReader? = null

    fun close() {
        if (!openFlag) {
            return
        }
        port?.close()
        port = null
        openFlag = false
        reader?.join()
    }

    private fun sendAck(dest: Int) {
        val buf = Frame.make(dest, Proto.Ack, emptyArray())
        port?.write(buf)
    }

    private fun waitResponse(timeout: Long): Frame {

        val frame = respSync.await(timeout)
        if (frame == null) {
            throw RespException("等待返回结果超时")
        }
        return frame
    }

    fun send(dest: Int, req: Int, args: Array<SerialType>, timeout: Long): Frame {
        write(dest, req, args)
        val frame = waitResponse(timeout)
        if (frame.request() != req) {
            throw IllegalStateException("req/res异常 ${frame.req.toHexStr4()} ${req.toHexStr4()}")
        }
        if (req == Proto.Delivery) {
            sendAck(dest)
        }
        return frame
    }

    fun write(dest: Int, req: Int, args: Array<SerialType>) {
        val buf = Frame.make(dest, req, args)
        write(buf)
    }

    private fun write(buf: ByteArray) {
        if (!openFlag) {
            throw IOException("串口没有打开")
        }
        respSync.clear()
        ackSync.clear()
        port!!.write(buf)
        val ret = ackSync.await(500)
        if (!ret) {
            throw AckException("没有收到ack")
        }
    }

    fun open(fn: (Boolean) -> Unit) {
        if (openFlag) {
            return
        }
        openFn = fn
        usbDevice = null
        val manager = AppContext.getSystemService(Context.USB_SERVICE) as UsbManager
        val devices = manager.deviceList.values
        for (dev in devices) {
            if (!FtdiSerialDevice.isSupport(dev)) {
                continue
            }
            usbDevice = dev
            break
        }
        if (usbDevice == null) {
            fn(false)
            return
        }
        val ret = manager.hasPermission(usbDevice!!)
        if (!ret) {
            val intent = Intent(USB_PERMISSION_ACTION)
            val filter = IntentFilter(USB_PERMISSION_ACTION)
            AppContext.registerReceiver(this, filter)
            val pi = PendingIntent.getBroadcast(AppContext, 0, intent, PendingIntent.FLAG_MUTABLE)
            manager.requestPermission(usbDevice!!, pi)
            return
        }
        openImpl()
    }

    private fun openImpl() {
        val manager = AppContext.getSystemService(Context.USB_SERVICE) as UsbManager
        if (!manager.hasPermission(usbDevice!!)) {
            openFn(false)
            return
        }
        val conn = manager.openDevice(usbDevice!!)
        val port = FtdiSerialDevice(usbDevice!!, conn)
        try {
            port.open()
            port.setParameters(
                38400,
                FtdiSerialDevice.DATABITS_8,
                FtdiSerialDevice.STOPBITS_1,
                FtdiSerialDevice.PARITY_NONE
            )
            this.port = port
            reader = PortReader(port, ackSync, respSync)
            reader?.start()
            openFlag = true
            openFn(true)
        } catch (e: Exception) {
            e.printStackTrace()
            openFn(false)
        }
    }

    override fun onReceive(p0: Context?, p1: Intent) {
        AppContext.unregisterReceiver(this)
        val ret = p1.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
        log("usb权限:$ret")
        openImpl()
    }
}




















